/* Autore: Nicola Agosti */
/*
Questo programma mostra:
 - come definire le funzioni con e senza valori di ritorno (procedure);
 - come passare uno o più parametri, per valore, alle funzioni;
 - la differenza tra variabili locali e variabili globali;
 - come si dichiara un prototipo di una funzione.
*/

#define _CRT_SECURE_NO_WARNINGS /* Necessario se utilizziamo Visual Studio */

#include <stdio.h>
#include <stdlib.h>

/*
Variabili globali
Variabili visibili e modificabili da tutte le funzioni presenti all'interno del file.
Per dichiarare una variabile globale la devo dichiarare al di fuori delle funzioni e del "main".
*/
int numGlobale;

/*
Prototipi delle funzioni
Le funzioni, come le variabili, devono essere dichiarate/definite prima di poter essere utilizzate.
Se non si vuole definire l'intera funzione prima di utilizzarla, si può dichiararne solo il prototipo.
Il prototipo è un'istruzione che dichiara "l'interfaccia" (nome, numero e tipo dei parametri
e tipo del valore di ritorno) della funzione... cioè dichiara la modalità con cui la funzione
può essere chiamata.
*/
void disegnaQuadrato(int); /* Procedura che disegna un quadrato di lato N di asterischi */
void disegnaTriangolo(int); /* Procedura che disegna un triangolo di lato N di asterischi */
void disegnaLinea(int); /* Procedura che disegna una linea di lunghezza N di asterischi */

int sommaDiDueNumeri(int, int); /* Funzione che ritorna la somma tra due numeri interi */
float mediaTraDueNumeri(int, int); /* Funzione che calcola la media tra due numeri interi */

void successivo(int); /* Procedura che calcola e stampa il numero successivo rispetto a quello passato come parametro */

void successivoConVariabileGlobale(); /* Procedura che calcola e stampa il numero successivo di quello contenuto nella variabile globale "numGlobale" */

int main()
{
	int somma, num;

	/* Esempio 1: disegna un quadrato di lato 5 e un triangolo di lato 7 di asterischi */
	printf("ESEMPIO 1\n");
	printf("\nQuadrato di lato 5\n");
	disegnaQuadrato(5);
	printf("\nTriangolo di lato 7\n");
	disegnaTriangolo(7);
	
	/* Esempio 2: ritorna la somma e la media tra 10 e 9 */
	printf("\n\nESEMPIO 2\n");
	somma = sommaDiDueNumeri(10, 9);
	printf("\nLa somma tra 10 e 9 e\' %d", somma);
	printf("\nLa media tra 10 e 9 e\' %.2f", mediaTraDueNumeri(10, 9));

	/* Esempio 3: significato di "passaggio per valore" di un parametro */
	printf("\n\n\nESEMPIO 3\n");
	num = 10;
	printf("\n\"num\" PRIMA della chiamata alla funzione \"successivo\" e\' %d", num);
	successivo(num);
	printf("\n\"num\" DOPO la chiamata alla funzione \"successivo\" e\' %d", num);

	/* Esempio 4: significato di "passaggio per valore" di un parametro */
	printf("\n\n\nESEMPIO 4\n");
	numGlobale = 5;
	printf("\n\"numGlobale\" PRIMA della chiamata alla funzione \"successivoConVariabileGlobale\" e\' %d", numGlobale);
	successivoConVariabileGlobale(numGlobale);
	printf("\n\"numGlobale\" DOPO la chiamata alla funzione \"successivoConVariabileGlobale\" e\' %d", numGlobale);

	printf("\n");

	return 0;
}

/* Procedura che disegna un quadrato di lato N di asterischi */
/*
Le procedure hanno:
 - un nome scritto con la stessa convenzione delle variabili;
 - "void" come tipo per il valore di ritorno (significa che non ritornano alcun valore);
 - una lista, a volte vuota, di parametri (dichiarati con tipo e nome) separati dalla virgola e 
   scritta tra le parentesi tonde.
*/
void disegnaQuadrato(int lato)
{
	int i;

	/* Per disegnare il quadrato richiamo la funzione "disegnaLinea" */
	for (i = 0; i < lato; i++)
	{
		disegnaLinea(lato);
	}
}

void disegnaTriangolo(int lato)
{
	int i;

	/* Per disegnare il triangolo richiamo la funzione "disegnaLinea" */
	for (i = 0; i < lato; i++)
	{
		disegnaLinea(i + 1);
	}
}

/* Procedura che disegna una linea di lunghezza N di asterischi */
void disegnaLinea(int lunghezza)
{
	int i;

	/* Per disegnare il quadrato richiamo la funzione "disegnaLinea" */
	for (i = 0; i < lunghezza; i++)
	{
		printf("*");
	}
	printf("\n");
}

/* Funzione che ritorna la somma tra due numeri interi */
/*
Le funzioni hanno:
 - un nome scritto con la stessa convenzione delle variabili;
 - un tipo (int, float, ecc.) per il valore di ritorno;
 - una lista, a volte vuota, di parametri (dichiarati con tipo e nome) separati dalla virgola e
   scritta tra le parentesi tonde.

Il valore viene ritornato dalla funzione a quella che l'ha invocata attraverso l'istruzione "return".
*/
int sommaDiDueNumeri(int num_1, int num_2)
{
	int somma;

	somma = num_1 + num_2;

	return somma;
}

/* Funzione che calcola la media tra due numeri interi */
float mediaTraDueNumeri(int num_1, int num_2)
{
	int somma;

	somma = sommaDiDueNumeri(num_1, num_2);

	return somma / 2.0;
}

/* Procedura che calcola e stampa il numero successivo rispetto a quello passato come parametro */
void successivo(int num)
{
	num++;

	printf("\n\"num\" all\'interno della funzione \"successivo\" dopo l\'incremento e\' %d", num);
}

/* Procedura che calcola e stampa il numero successivo di quello contenuto nella variabile globale "numGlobale" */
void successivoConVariabileGlobale()
{
	numGlobale++;

	printf("\n\"numGlobale\" all\'interno della funzione \"successivoConVariabileGlobale\" dopo l\'incremento e\' %d", numGlobale);
}